import { TGateway, getBucketAccessUrl } from '@/api/oss';
import { ElNotification } from 'element-plus';
import { isArray } from 'microconnect-common/utils/is';
import { TOKEN_STORAGE_KEY } from '@/constants/config';
import storage from '@/utils/storage';
// import { getLocal } from 'microconnect-common/utils/storage';

export type TFileList = 'png' | 'jpg' | 'jpeg' | 'zip' | 'xlsx' | 'xls' | 'doc' | 'docx' | 'txt' | 'pdf' | 'mp4';

export const fileList: TFileList[] = ['png', 'jpg', 'jpeg', 'zip', 'xlsx', 'xls', 'doc', 'docx', 'txt', 'pdf', 'mp4'];

export type TImageUrlToBase64List = 'png' | 'jpg' | 'jpeg' | 'bmp';

export const acceptType: Record<TFileList, string> = {
  png: 'image/png',
  jpg: 'image/jpeg',
  jpeg: 'image/jpeg',
  zip: 'application/zip',
  xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  xls: 'application/vnd.ms-excel',
  doc: '.doc,application/msword',
  docx: '.docx,application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  txt: 'text/plain',
  pdf: 'application/pdf',
  mp4: 'video/mp4'
};

export const toAcceptType = (typeList: TFileList[]) => {
  return typeList
    .map((type) => {
      return acceptType[type];
    })
    .filter(Boolean)
    .join(',');
};

/** 根据链接获取文件类型 */
export const getFileType = (url = '') => {
  const [filePath = ''] = String(url).split('?');
  return (filePath.substr(filePath.lastIndexOf('.') + 1) || '').toLowerCase().trim();
};

/**
 * 取相对路径最后一个 `/` 后的 32位，作为文件名
 */
export const getFileName = (path: string) => {
  const endStr = String(path).split('/').pop();
  let [fileName] = endStr?.slice(32)?.split('?') || [];
  if (!fileName) {
    fileName = endStr || '';
  }
  try {
    fileName = decodeURIComponent(fileName);
  } catch (e) {}
  return fileName;
};

/**
 * 是否PDF
 * @param url 链接
 * @returns { Boolean }
 */
export const isPdf = (url: string) => getFileType(url) === 'pdf';

/**
 * 是否图片
 * @param url 链接
 * @returns { Boolean }
 */
export const isImage = (url: string) => {
  const type = getFileType(url);
  return ['png', 'jpg', 'jpeg'].some((t) => t === type);
};

/**
 * 是否视频
 * @param url 链接
 * @returns { Boolean }
 */
export const isVideo = (url: string) => {
  const type = getFileType(url);
  return ['mp4', 'ogg', 'wmv'].some((t) => t === type);
};

/**
 * 是否XLS文件
 * @param url 链接
 * @returns { Boolean }
 */
export const isXls = (url: string) => {
  const type = getFileType(url);
  return ['xls', 'xlsx'].some((t) => t === type);
};

/**
 * 是否Txt文件
 * @param url 链接
 * @returns { Boolean }
 */
export const isTxt = (url: string) => {
  const type = getFileType(url);
  return ['txt'].some((t) => t === type);
};

/**
 * 是否DOC文件
 * @param url 链接
 * @returns { Boolean }
 */
export const isDoc = (url: string) => {
  const type = getFileType(url);
  return ['doc', 'docx'].some((t) => t === type);
};

/**
 * 是否ZIP文件
 * @param url 链接
 * @returns { Boolean }
 */
export const isZip = (url: string) => {
  const type = getFileType(url);
  return ['zip'].some((t) => t === type);
};

/**
 * 将oss相对路径转绝对路径
 * @param gateway 网关
 * @param url url
 * @returns 绝对路径
 */
export const toAccessUrl = async (gateway: TGateway, url = '', isAll = false) => {
  if (url?.indexOf('http') === -1) {
    return await getBucketAccessUrl(gateway, url, isAll);
  }
  return url;
};

/**
 * 文件下载失败
 */
const downloadFileFailure = (xhr: XMLHttpRequest) => {
  const fileReader = new FileReader();

  fileReader.readAsText(xhr.response);

  fileReader.onload = function () {
    try {
      const message = JSON.parse(<any>this.result).message;
      ElNotification.error(message);
    } catch {
      ElNotification.error('文件下载失败，请重试！');
    }
  };
};

// /**
//  * 文件正常下载
//  */
// const downloadFileSuccess = (xhr: XMLHttpRequest, fileName: string = '') => {
//   const fileReader = new FileReader();

//   fileReader.readAsDataURL(xhr.response);

//   fileReader.onload = function () {
//     const a: any = document.createElement('a');

//     a.style.display = 'none';

//     a.href = this.result;

//     let name = fileName;

//     const resFileName = xhr?.getResponseHeader('content-disposition')?.split('filename=')[1];

//     if (!name && resFileName) {
//       // 下载excel未传入文件名且后端有在响应头设置文件名时，取后端文件名
//       name = decodeURIComponent(resFileName);
//     }

//     a.download = decodeURIComponent(name.replace(/^["|'](.*)["|']$/g, '$1'));

//     document.body.appendChild(a);

//     a.click();

//     document.body.removeChild(a);
//   };
// };

// /**
//  * @desc 下载文件
//  * @param path 下载地址
//  * @param fileName 文件名称（不传则使用后台传过来的文件名称）
//  */
// export const downloadFile = (
//   method: 'get' | 'post',
//   path: string,
//   fileName: string,
//   params?: string,
//   onSuccess?: TAnyFunction,
//   onError?: TAnyFunction
// ) => {
//   const xhr = new XMLHttpRequest();
//   xhr.open(method, path);
//   if (method === 'post') {
//     xhr.setRequestHeader('Content-Type', 'application/json');
//   }
//   xhr.responseType = 'blob';
//   // 设置头部鉴权信息
//   xhr.setRequestHeader('Authorization', `Bearer ${getLocal('token')}`);
//   xhr.send(params);
//   xhr.onload = function () {
//     if ([304, 200, 201].includes(this.status)) {
//       if (this.response.type === 'application/json') {
//         // 后台返回的响应数据类型为【application/json】代表下载异常，抛出异常错误信息
//         downloadFileFailure(this);
//         onError?.();
//       } else {
//         downloadFileSuccess(this, fileName);
//         onSuccess?.();
//       }
//     } else if ([500, 404].includes(this.status)) {
//       onError?.();
//     }
//   };
//   if (onError) xhr.onerror = onError;
// };

/**
 * @desc 下载文件
 * @param path 下载地址
 * @param fileName 文件名称（不传则使用后台传过来的文件名称）
 */
export const downloadFile = (path: string, fileName?: string, errorCb?: TAnyFunction, successCb?: TAnyFunction) => {
  const xhr = new XMLHttpRequest();
  xhr.open('get', path);
  xhr.responseType = 'blob';
  // 设置头部鉴权信息
  xhr.setRequestHeader('Authorization', `Bearer ${storage.get(TOKEN_STORAGE_KEY)}`);
  xhr.send();
  xhr.onload = function () {
    if ([304, 200, 201].includes(this.status)) {
      const name = fileName || xhr?.getResponseHeader('Content-Disposition')?.split('filename=')[1];
      if (!name) {
        ElNotification({
          type: 'error',
          message: '下载失败'
        });
        errorCb?.();
        return;
      }
      const fileReader = new FileReader();
      fileReader.readAsDataURL(this.response);
      fileReader.onload = function () {
        const a: any = document.createElement('a');
        a.style.display = 'none';
        a.href = this.result;
        // 使用后端传的文件名，先 decode，再把前后引号去掉
        a.download = decodeURIComponent(name.replace(/^["|'](.*)["|']$/g, '$1'));
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        successCb?.();
      };
    } else if ([500, 401, 400, 404].includes(this.status)) {
      errorCb?.();
    }
  };
};

// 处理查询数据时 上传字段为字符串的时候
export const uploadValueTrans = (val: string | string[]) => {
  if (!val) {
    return [''];
  }

  if (isArray(val)) return val as string[];
  val = JSON.parse(val);

  return [val] as string[];
};

// 获取oss文件名称
export const getOssFileName = (url: string = '') => {
  const [filePath = ''] = url?.split('/').slice(-1) || [];
  let [fileName] = filePath.split('?') || [''];
  if (fileName.length > 32) {
    fileName = fileName.slice(32);
  }
  return fileName;
};

// 根据资源地址下载到本地
export const downloadFileByUrl = async (url: string, filename?: string) => {
  const aEl = document.createElement('a');
  aEl.setAttribute('href', 'javascript:;');
  aEl.setAttribute('download', filename ?? '文件');
  if (url) {
    await fetch(url)
      .then((res) => res.blob())
      .then((blob) => {
        url = window.URL.createObjectURL(blob);
        aEl.setAttribute('href', url);
        aEl.click();
      });
  }
};
const parseBase64 = (base64: string) => {
  const arr = base64.split(',');
  const mime = arr[0].match(/:(.*?);/)?.[1];
  return {
    mime,
    data: arr[1]
  };
};
const base64ToUint8Array = (base64: string) => {
  const parsedBase64 = parseBase64(base64);
  const bstr = atob(parsedBase64.data);
  let n = bstr.length;
  const u8arr = new Uint8Array(n);

  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }

  return u8arr;
};

export const base64ToBlob = (base64: string) => {
  const parsedBase64 = parseBase64(base64);
  const u8arr = base64ToUint8Array(base64);
  return new Blob([u8arr], { type: parsedBase64.mime });
};

/**
 * 文件转 base64
 * @param file
 * @returns
 */
export const fileToBase64Async = (file: File) => {
  return new Promise(async (resolve) => {
    let reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = (e) => {
      const strBase64 = e.target?.result;
      resolve(strBase64);
    };
  });
};

/**
 * 图片url转 base64
 * @param url
 * @returns
 */
export const getBase64ImageUrl = (imageUrl: string, imgType?: TImageUrlToBase64List) => {
  return new Promise<string>((resolve) => {
    if (!imgType) {
      imgType = 'png';
    }

    let dataURL = '';
    const Img = new Image();
    const random: number = Math.random();
    Img.src = `${imageUrl}?v=${random}`;
    Img.setAttribute('crossOrigin', 'Anonymous');
    Img.onload = async () => {
      const canvas = document.createElement('canvas');
      const { width, height } = Img;
      canvas.width = width;
      canvas.height = height;
      canvas.getContext('2d')!.drawImage(Img, 0, 0, width, height);
      dataURL = canvas.toDataURL(`image/${imgType}`);
      resolve(dataURL);
    };
  });
};

/**
 * @desc 下载文件
 * @param path 下载地址
 * @param fileName 文件名称（不传则使用后台传过来的文件名称）
 * @params 接口参数，如果是 body参数则 传入 JSON.stringify({xx:1}) 之后的值
 * @onSuccess 成功回调
 * @onError 失败回调
 */
interface IDownloadFileByFetchOptions {
  method: 'GET' | 'POST';
  path: string;
  fileName?: string;
  params?: Record<string, string>;
  onSuccess?: TAnyFunction;
  onError?: TAnyFunction;
}

export const downloadFileByFetch = ({
  method,
  path,
  fileName,
  params,
  onSuccess,
  onError
}: IDownloadFileByFetchOptions) => {
  const xhr = new XMLHttpRequest();
  let url = path;
  // 如果是 GET 请求，将参数添加到 URL 中

  if (method === 'GET' && params) {
    const filteredParams = Object.fromEntries(
      Object.entries(params).filter(([key, value]) => !['', undefined, null].includes(value))
    );
    url += '?' + new URLSearchParams(filteredParams).toString();
  }

  xhr.open(method, url);
  xhr.responseType = 'blob';
  xhr.setRequestHeader('Authorization', `Bearer ${storage.get(TOKEN_STORAGE_KEY)}`);

  // 如果是 POST 请求，设置 Content-Type 头部并发送 JSON 数据
  if (method === 'POST') {
    xhr.setRequestHeader('Content-Type', 'application/json');
    xhr.send(JSON.stringify(params));
  } else {
    xhr.send();
  }

  xhr.onload = function () {
    if ([304, 200, 201].includes(this.status)) {
      if (this.response.type === 'application/json') {
        onError?.();
        return downloadFileFailure(this);
      }
      const name = fileName ? fileName : (xhr?.getResponseHeader('content-disposition')?.split('filename=')[1] as string);
      const fileReader = new FileReader();
      fileReader.readAsDataURL(this.response);
      fileReader.onload = function () {
        const a: any = document.createElement('a');
        a.style.display = 'none';
        a.href = this.result;
        // 使用后端传的文件名，先 decode，再把前后引号去掉
        a.download = decodeURIComponent(name.replace(/^["|'](.*)["|']$/g, '$1'));
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        onSuccess?.();
      };
    } else if ([400, 401, 500].includes(this.status)) {
      onError?.();
      return downloadFileFailure(this);
    }
  };
  if (onError) xhr.onerror = onError;
};
